package hi.chyl.json;

import com.google.gson.JsonElement;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Image;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.dnd.DnDConstants;
import java.awt.dnd.DropTarget;
import java.awt.dnd.DropTargetDragEvent;
import java.awt.dnd.DropTargetDropEvent;
import java.awt.dnd.DropTargetEvent;
import java.awt.dnd.DropTargetListener;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.swing.BorderFactory;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JComboBox;
import javax.swing.event.ListDataEvent;
import org.jdesktop.application.SingleFrameApplication;
import org.jdesktop.application.FrameView;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTabbedPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.JToolBar;
import javax.swing.JTree;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
import javax.swing.text.Document;
import javax.swing.text.JTextComponent;
import javax.swing.text.Segment;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreeNode;
import javax.swing.tree.TreePath;
import org.apache.commons.lang.StringEscapeUtils;
import org.apache.commons.lang.StringUtils;
import org.jdesktop.application.Application;
import org.jdesktop.application.ApplicationActionMap;
import org.jdesktop.application.ResourceMap;
import org.netbeans.swing.tabcontrol.DefaultTabDataModel;
import org.netbeans.swing.tabcontrol.TabData;
import org.netbeans.swing.tabcontrol.TabDataModel;
import org.netbeans.swing.tabcontrol.TabbedContainer;
import org.netbeans.swing.tabcontrol.event.ComplexListDataEvent;
import org.netbeans.swing.tabcontrol.event.ComplexListDataListener;

public class MainView extends FrameView implements DropTargetListener
{
    private JDialog aboutBox;
    private TabDataModel tabDataModel;
    private TabbedContainer tabbedContainer;
    public static final Map<Integer, JsonElement> JSON_MAP = new HashMap<Integer, JsonElement>();
    private List<TreePath> treePathLst = new ArrayList<TreePath>();
    private int curPos = 0;
    private ResourceMap resMap;
    private JComboBox urlField;
    private ApplicationActionMap actionMap;
    private JLabel statusAnimationLabel;
    private JDialog findDialog;
    private boolean autoRenameTab = true;
    private JMenu recentFilesMenu;  // 菜单项-最近打开的文件
    Image ico = new ImageIcon(getClass().getResource("resources/json.png")).getImage();

    public MainView(SingleFrameApplication app)
    {
        super(app);
        resMap = Application.getInstance(MainApp.class).getContext().getResourceMap(MainView.class);
        actionMap = Application.getInstance().getContext().getActionMap();
        recentFilesMenu = new JMenu($("recentFilesMenu.text"));
        initUI();
        initRecentFiles();
        new DropTarget(getComponent(), DnDConstants.ACTION_COPY_OR_MOVE, this);
    }
    
    public String $(String key)
    {
        return resMap.getString(key);
    }

    public String $(String key, Object... args)
    {
        return resMap.getString(key, args);
    }
    
    public Icon $icon(String key)
    {
        return resMap.getIcon(key);
    }
    
    private void initRecentFiles()
    {
        String filesStr = MainApp.conf.getProperty("recent");
        if (!StringUtils.isEmpty(filesStr))
        {
            String[] files = filesStr.split(";");
            if (files == null)
            {
                return ;
            }
            for (int i = files.length - 1; i >= 0; i--)
            {
                File f = new File(files[i]);
                addRecentFile(f);
            }
        }
    }
    
    private void updateRecentFiles()
    {
        StringBuilder recents = new StringBuilder();
        for (int i = 0; i < recentFilesMenu.getMenuComponentCount(); i++)
        {
            JMenuItem item = recentFilesMenu.getItem(i);
            recents.append(item.getName()).append(";");
        }
        MainApp.conf.setProperty("recent", recents.toString());
    }
    
    private void initUI()
    {
        getFrame().setIconImage(ico);
        setToolBar(createToolBar());
        setMenuBar(createMenuBar());
        initTabbedContainer();
        setComponent(tabbedContainer);

        // 窗口打开时，textarea获得焦点
        getFrame().addWindowListener(new WindowAdapter()
        {
            @Override
            public void windowOpened(WindowEvent e)
            {
                focusOnEditor();
            }
        });

        initFindDialog();
    }

    private void initUrls()
    {
        BufferedReader reader = null;
        String url = "";
        File file = new File("url.txt");

        try {
            if (file.exists())
                reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF-8"));
            else 
                reader = new BufferedReader(new InputStreamReader(ClassLoader.getSystemResourceAsStream("url.txt"), "UTF-8"));
        } catch (Exception ex) {
            ex.printStackTrace();
        }

        if (reader == null)
            return;

        try
        {
            while ((url = reader.readLine()) != null)
            {
                if ("".equals(url.trim()) || url.startsWith("#"))
                {
                    continue;
                }
                urlField.addItem(url);
            }
        } catch (IOException e)
        {
        } finally
        {
            try
            {
                reader.close();
            } catch (Exception ee)
            {
            }
        }
    }

    private JToolBar createToolBar()
    {
        JToolBar toolbar = new JToolBar();
        toolbar.setFloatable(false);
        final JTextField textField = new JTextField();
        textField.setMaximumSize(new Dimension(180, 25));
        JButton btnAppTitle = new JButton("标题修改");
        JButton btnFormat = new JButton("格式化", $icon("format.icon"));
        JButton btnClean = new JButton("清空", $icon("clean.icon"));
        JButton btnParse = new JButton("粘帖", $icon("paste.icon"));
        JButton btnNewLine = new JButton("清除空白", $icon("deleten.icon"));
        JButton btnTxtFind = new JButton("查找", $icon("find.icon"));
        JButton btnNewTab = new JButton("新标签", $icon("newtab.icon"));
        JButton btnSelTabName = new JButton("重命名", $icon("deleten.icon"));
        JButton btnCloseTab = new JButton("关闭标签");
        JButton btnSend = new JButton("发送", $icon("send.icon"));
        JButton btnStop = new JButton("取消", $icon("cancel.icon"));

        statusAnimationLabel = new JLabel();
        statusAnimationLabel.setHorizontalAlignment(javax.swing.SwingConstants.LEFT);

        urlField = new JComboBox();
        urlField.setEditable(true);
        urlField.setMaximumSize(new Dimension(450, 25));
        Font font = urlField.getFont();
        urlField.setFont(new Font(font.getName(), 0, 15));
        Component urlFieldEditor = urlField.getEditor().getEditorComponent();
        if (urlFieldEditor instanceof JTextComponent)
        {
            ((JTextComponent) urlFieldEditor).setComponentPopupMenu(TextActions.createTextPopMenu());
        }
        initUrls();

        btnAppTitle.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent e)
            {
                System.out.println(textField.getText());
                getFrame().setTitle(textField.getText());
            }
        });
        
        btnFormat.setToolTipText("格式化JSON代码  (Ctrl+Shift+F)");
        btnFormat.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent e)
            {
                format();
            }
        });

        btnClean.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent e)
            {
                JTextArea ta = getActiveEditor();
                if (ta != null)
                {
                    ta.replaceRange("", 0, ta.getText().length());
                }
            }
        });

        btnParse.setToolTipText("粘贴并格式化JSON代码  (Ctrl+Shift+V)");
        btnParse.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent e)
            {
                JTextArea ta = getActiveEditor();
                if (ta != null)
                {
                    ta.paste();
                    format();
                }
            }
        });

        btnNewLine.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent e)
            {
                JTextArea ta = getActiveEditor();
                if (ta != null)
                {
                    ta.setText(ta.getText().replaceAll("\\s", ""));
                }
            }
        });

        btnTxtFind.setToolTipText("查找文本或节点  (Ctrl+F)");
        btnTxtFind.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent e)
            {
                MainApp.getApplication().show(findDialog);
            }
        });

        btnSelTabName.setToolTipText("修改当前标签页标题  (Ctrl+R)");
        btnSelTabName.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent e)
            {
                int selIndex = getTabIndex();
                if (selIndex >= 0)
                {
                    showRenameTabDialog(selIndex);
                }
            }
        });

        btnNewTab.setToolTipText("新建标签页  (Ctrl+N)");
        btnNewTab.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent e)
            {
                addTab("新建标签", true, $icon("tab.icon1"));
            }
        });

        btnCloseTab.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent e)
            {
                int selIndex = getTabIndex();
                if (selIndex >= 0)
                {
                    tabDataModel.removeTab(selIndex);
                }
            }
        });

        btnSend.setToolTipText("发送请求  (Ctrl+Enter)");
        btnSend.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent e)
            {
                sendRequest();
            }
        });

        btnStop.setToolTipText("取消请求");
        btnStop.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent e)
            {
                stopRequest();
            }
        });


        toolbar.add(btnNewTab);
        toolbar.add(btnFormat);
        toolbar.add(btnSelTabName);
        toolbar.add(btnClean);
        toolbar.add(btnParse);
        toolbar.add(btnTxtFind);
        toolbar.addSeparator(new Dimension(20, 26));
        toolbar.add(urlField);
        toolbar.add(btnSend);
        toolbar.add(btnStop);
        toolbar.add(statusAnimationLabel);

        // 工具栏里的组件，除了URL地址栏可以获得焦点，其它组件均不可获得焦点
        Component[] comps = toolbar.getComponents();
        for (Component c : comps)
        {
            c.setFocusable(c == urlField);
        }
        return toolbar;
    }

    /**
     * 格式化当前活动的标签页
     */
    private void format()
    {
        getActiveJsonPanel().formatJson();
        // 自动重命名标签，如果标签页是打开的文件，则不自动重命名
        if (autoRenameTab && null == getActiveContentPanel().file)
        {
            String title = getActiveJsonPanel().getNodeValue("Request-BusiCode");
            if (title != null)
            {
                tabDataModel.setText(getTabIndex(), title);
            }
        }
    }

    /**
     * 发送接口请求
     */
    public void sendRequest()
    {
        String url = null;
        Object item = urlField.getSelectedItem();
        if (null == item || "".equals(item.toString().trim()))
        {
            JOptionPane.showMessageDialog(null, "请输入URL！", "错误", JOptionPane.ERROR_MESSAGE);
            return;
        }
        url = item.toString().trim().split(" ")[0];

        getActiveContentPanel().sendRequest(url);
    }

    /**
     * 停止接口请求
     */
    public void stopRequest()
    {
        getActiveContentPanel().stopRequest();
    }

    /**
     * 文本查找面板
     * @return 
     */
    private JPanel createTextFindPanel()
    {
        JPanel panel = new JPanel();
        FlowLayout layout = new FlowLayout(FlowLayout.LEFT);
        panel.setLayout(layout);
        panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
        JLabel label = new JLabel("查找内容: ");
        JButton btnFind = new JButton("查找");
        JButton btnNext = new JButton("下一个");
        JButton btnPrev = new JButton("上一个");
        final JTextField textFieldFind = new JTextField(40);
        textFieldFind.setComponentPopupMenu(TextActions.createTextPopMenu());
        panel.add(label);
        panel.add(textFieldFind);
        panel.add(btnFind);
        panel.add(btnPrev);
        panel.add(btnNext);

        //从头开始查找
        btnFind.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent e)
            {
                boolean flag = false;
                modifyDialgTitle(findDialog, flag, -1);
                flag = startSegmentFindOrReplaceOperation(getActiveEditor(), textFieldFind.getText(), true, true, true);
                modifyDialgTitle(findDialog, flag, 1);
            }
        });

        //向下查找
        btnNext.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent e)
            {
                boolean flag = false;
                modifyDialgTitle(findDialog, flag, -1);
                flag = startSegmentFindOrReplaceOperation(getActiveEditor(), textFieldFind.getText(), true, true, false);
                modifyDialgTitle(findDialog, flag, 1);
            }
        });

        //向上查找
        btnPrev.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent e)
            {
                boolean flag = false;
                modifyDialgTitle(findDialog, flag, -1);
                flag = startSegmentFindOrReplaceOperation(getActiveEditor(), textFieldFind.getText(), true, false, false);
                modifyDialgTitle(findDialog, flag, 1);
            }
        });

        return panel;
    }

    /**
     * 树节点查找面板
     * @return 
     */
    private JPanel createNodeFindpPanel()
    {
        JPanel panel = new JPanel();
        FlowLayout layout = new FlowLayout(FlowLayout.LEFT);
        panel.setLayout(layout);
        panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
        JButton btnFind = new JButton("查找");
        JButton btnNext = new JButton("下一个");
        JButton btnPrev = new JButton("上一个");
        JLabel label = new JLabel("查找节点: ");
        final JTextField textFieldFind = new JTextField(40);
        textFieldFind.setComponentPopupMenu(TextActions.createTextPopMenu());
        panel.add(label);
        panel.add(textFieldFind);
        panel.add(btnFind);
        panel.add(btnPrev);
        panel.add(btnNext);

        //从头开始查找
        btnFind.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent e)
            {
                boolean flag = false;
                modifyDialgTitle(findDialog, flag, -1);
                findTreeChildValue(textFieldFind.getText(), treePathLst);
                if (!treePathLst.isEmpty())
                {
                    flag = true;
                }
                modifyDialgTitle(findDialog, flag, 1);
            }
        });

        //向下查找
        btnNext.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent e)
            {
                boolean flag = false;
                modifyDialgTitle(findDialog, flag, -1);
                JTree tree = getTree();
                curPos++;
                if (curPos < treePathLst.size())
                {
                    tree.setSelectionPath(treePathLst.get(curPos));
                    tree.scrollPathToVisible(treePathLst.get(curPos));
                    flag = true;
                } else
                {
                    curPos = treePathLst.size() - 1;
                }
                modifyDialgTitle(findDialog, flag, 1);
            }
        });

        //向上查找
        btnPrev.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent e)
            {
                boolean flag = false;
                JTree tree = getTree();
                modifyDialgTitle(findDialog, flag, -1);
                curPos--;
                if (curPos >= 0)
                {
                    tree.setSelectionPath(treePathLst.get(curPos));
                    tree.scrollPathToVisible(treePathLst.get(curPos));
                    flag = true;
                } else
                {
                    curPos = 0;
                }
                modifyDialgTitle(findDialog, flag, 1);
            }
        });

        return panel;
    }

    /**
     * 初始化查找对话框
     */
    private void initFindDialog()
    {
        findDialog = new JDialog(getFrame());
        findDialog.setTitle("查找对话框");
        findDialog.setModal(false);
        findDialog.setSize(500, 70);
        findDialog.setResizable(false);
        findDialog.setIconImage(ico);

        JTabbedPane tabPane = new JTabbedPane();
        tabPane.addTab("文本查找(T)", createTextFindPanel());
        tabPane.addTab("节点查找(N)", createNodeFindpPanel());

        JPanel pane = new JPanel();
        pane.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
        pane.setLayout(new BorderLayout());
        pane.add(tabPane, BorderLayout.CENTER);

        findDialog.getContentPane().add(pane);

        findDialog.addWindowListener(new WindowAdapter()
        {
            @Override
            public void windowClosing(WindowEvent e)
            {
                treePathLst.clear();
                System.gc();
            }
        });
    }
    
    /**
     * 显示重命名标签标题对话框
     * @param index 
     */
    private void showRenameTabDialog(final int index)
    {
        final JDialog renameDialog = new JDialog(getFrame());
        JPanel pane = new JPanel();
        pane.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
        pane.setLayout(new FlowLayout(FlowLayout.LEFT));
        JLabel label = new JLabel("新标签名: ");
        final JTextField field = new JTextField();
        field.setPreferredSize(new Dimension(200, 20));
        field.setComponentPopupMenu(TextActions.createTextPopMenu());
        JButton button = new JButton("确定");
        pane.add(label);
        pane.add(field);
        pane.add(button);
        renameDialog.getContentPane().add(pane);
        renameDialog.setTitle("重命名标签");
        renameDialog.setModal(true);
        renameDialog.setResizable(false);
        renameDialog.setIconImage(ico);

        String title = tabDataModel.getTab(index).getText();
        field.setText(title);
        field.selectAll();

        button.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent e)
            {
                String text = field.getText();
                if (StringUtils.isEmpty(text))
                {
                    JOptionPane.showMessageDialog(null, "请输入新的标签标题！", "错误", JOptionPane.ERROR_MESSAGE);
                    return;
                }
                tabDataModel.setText(index, text);
                renameDialog.dispose();
            }
        });

        field.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent e)
            {
                String text = field.getText();
                if (StringUtils.isEmpty(text))
                {
                    JOptionPane.showMessageDialog(null, "请输入新的标签标题！", "错误", JOptionPane.ERROR_MESSAGE);
                    return;
                }
                tabDataModel.setText(index, text);
                renameDialog.dispose();
            }
        });

        MainApp.getApplication().show(renameDialog);
    }

    /**
     * 当前标签的index
     * @return 
     */
    private int getTabIndex()
    {
        return tabbedContainer.getSelectionModel().getSelectedIndex();
    }

    private JMenuItem createMenuItem(String name, int keyCode)
    {
        JMenuItem menuItem = new JMenuItem();
        menuItem.setAccelerator(KeyStroke.getKeyStroke(keyCode, InputEvent.CTRL_MASK));
        menuItem.setText($(name + ".text"));
        menuItem.setMnemonic(keyCode);
        return menuItem;
    }

    private JMenuBar createMenuBar()
    {
        JMenuBar menuBar = new JMenuBar();
        JMenu fileMenu = new JMenu();
        JMenu editMenu = new JMenu();
        JMenu toolMenu = new JMenu();
        JMenu helpMenu = new JMenu();

        menuBar.setName("menuBar");


        fileMenu.setText($("fileMenu.text"));
        fileMenu.setMnemonic('F');
        fileMenu.setName("fileMenu");

        JMenuItem menuItemNew = createMenuItem("menuItemNew", KeyEvent.VK_N);
        menuItemNew.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent evt)
            {
                addTab("新建标签", true, $icon("tab.icon1"));
            }
        });

        fileMenu.add(menuItemNew);

        JMenuItem menuItemOpenFile = createMenuItem("menuItemOpenFile", KeyEvent.VK_O);
        menuItemOpenFile.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent evt)
            {
                openFileAction();
            }
        });
        fileMenu.add(menuItemOpenFile);

        JMenuItem menuItemSaveFile = createMenuItem("menuItemSaveFile", KeyEvent.VK_S);
        menuItemSaveFile.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent evt)
            {
                saveFileAction(getActiveEditor().getText());
            }
        });
        fileMenu.add(menuItemSaveFile);
        
        JMenuItem menuItemSaveFileAs = createMenuItem("menuItemSaveFileAs", KeyEvent.VK_A);
        menuItemSaveFileAs.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent evt)
            {
                saveFileAsAction(getActiveEditor().getText());
            }
        });
        fileMenu.add(menuItemSaveFileAs);

        recentFilesMenu.setMnemonic('R');
        fileMenu.add(recentFilesMenu);

        fileMenu.addSeparator();

        JMenuItem exitMenuItem = new JMenuItem();
        exitMenuItem.setAction(actionMap.get("quit"));
        exitMenuItem.setName("exitMenuItem");
        exitMenuItem.setText($("exitMenu.text"));
        fileMenu.add(exitMenuItem);

        menuBar.add(fileMenu);

        editMenu.setText($("editMenu.text"));
        editMenu.setMnemonic('E');
        
        JMenuItem menuItemFormat = new JMenuItem($("menuItemFormat.text"));
        menuItemFormat.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F, KeyEvent.CTRL_MASK | KeyEvent.SHIFT_MASK));
        menuItemFormat.setMnemonic('F');
        menuItemFormat.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent evt)
            {
                format();
            }
        });
        editMenu.add(menuItemFormat);
        
        JMenuItem menuItemParse = new JMenuItem($("menuItemParse.text"));
        menuItemParse.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_V, KeyEvent.CTRL_MASK | KeyEvent.SHIFT_MASK));
        menuItemParse.setMnemonic('V');
        menuItemParse.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent evt)
            {
               getActiveEditor().paste();
               format();
            }
        });
        editMenu.add(menuItemParse);

        JMenuItem menuItemFind = createMenuItem("menuItemFind", KeyEvent.VK_F);
        menuItemFind.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent evt)
            {
                MainApp.getApplication().show(findDialog);
            }
        });
        editMenu.add(menuItemFind);

        JMenuItem menuItemClean = createMenuItem("menuItemClean", KeyEvent.VK_D);
        menuItemClean.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent evt)
            {
                getActiveEditor().setText("");
            }
        });
        editMenu.add(menuItemClean);

        menuBar.add(editMenu);

        toolMenu.setText($("toolMenu.text"));
        toolMenu.setMnemonic('T');
        
        JMenuItem menuItemSend = createMenuItem("menuItemSend", KeyEvent.VK_ENTER);
        menuItemSend.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent evt)
            {
                sendRequest();
            }
        });
        toolMenu.add(menuItemSend);
        
        JMenuItem menuItemStop = createMenuItem("menuItemStop", KeyEvent.VK_P);
        menuItemStop.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent evt)
            {
               stopRequest();
            }
        });
        toolMenu.add(menuItemStop);
        
        toolMenu.addSeparator();
        
        JMenuItem menuItemSwitchPanel = new JMenuItem($("menuItemSwitchPanel.text"));
        menuItemSwitchPanel.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F2, 0));
        menuItemSwitchPanel.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent evt)
            {
                switchPanel();
            }
        });
        toolMenu.add(menuItemSwitchPanel);

        JMenuItem menuItemLayout = createMenuItem("menuItemLayout", KeyEvent.VK_L);
        menuItemLayout.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent evt)
            {
                getActiveContentPanel().getRequestPanel().changeLayout();
                getActiveContentPanel().getResponsePanel().changeLayout();
            }
        });
        toolMenu.add(menuItemLayout);

        JMenuItem menuItemCode = createMenuItem("menuItemCode", KeyEvent.VK_T);
        menuItemCode.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent evt)
            {
                codeChangeAction();
            }
        });
        toolMenu.add(menuItemCode);
        
        JMenuItem menuItemRename = createMenuItem("menuItemRename", KeyEvent.VK_R);
        menuItemRename.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent evt)
            {
                showRenameTabDialog(getTabIndex());
            }
        });
        toolMenu.add(menuItemRename);
        
        final JMenuItem menuItemAutoRename = new JCheckBoxMenuItem($("menuItemAutoRename.text"));
        menuItemAutoRename.setSelected(true);
        menuItemAutoRename.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_I, InputEvent.CTRL_MASK));
        menuItemAutoRename.setMnemonic(KeyEvent.VK_I);
        menuItemAutoRename.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent e)
            {
                autoRenameTab = menuItemAutoRename.isSelected();
            }
        });
        toolMenu.add(menuItemAutoRename);

        menuBar.add(toolMenu);

        helpMenu.setText($("helpMenu.text"));
        helpMenu.setName("helpMenu");
        helpMenu.setMnemonic('H');

        JMenuItem aboutMenuItem = new JMenuItem();
        aboutMenuItem.setText($("aboutMenu.text"));
        aboutMenuItem.setName("aboutMenuItem");
        aboutMenuItem.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent e)
            {
                showAboutBox();
            }
        });
        helpMenu.add(aboutMenuItem);

        menuBar.add(helpMenu);

        return menuBar;
    }

    private void initTabbedContainer()
    {
        TabData tabData = newTabData("新建标签", "", $icon("tab.icon1"));
        tabDataModel = new DefaultTabDataModel(new TabData[] { tabData });
        tabbedContainer = new TabbedContainer(tabDataModel, TabbedContainer.TYPE_EDITOR);
        tabbedContainer.getSelectionModel().setSelectedIndex(0);
        tabbedContainer.setShowCloseButton(true);
        tabDataModel.addComplexListDataListener(new ComplexListDataListener()
        {
            public void indicesAdded(ComplexListDataEvent clde)
            {
            }

            public void indicesRemoved(ComplexListDataEvent clde)
            {
            }

            public void indicesChanged(ComplexListDataEvent clde)
            {
            }

            public void intervalAdded(ListDataEvent e)
            {
            }

            public void intervalRemoved(ListDataEvent e)
            {
                ComplexListDataEvent ce = (ComplexListDataEvent) e;
                TabData[] tbArr = ce.getAffectedItems();
                if (tbArr != null && tbArr.length > 0)
                {
                    tbArr[0].getText();
                    JTree tree = getTree(tbArr[0]);
                    if (tree != null)
                    {
                        JSON_MAP.remove(tree.hashCode());
                        System.out.println("Remove HashCode: " + tree.hashCode() + ". Close Tab: " + tbArr[0].getText() + " !");
                    }
                    focusOnEditor();
                }
            }

            public void contentsChanged(ListDataEvent e)
            {
            }
        });

        tabbedContainer.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent e)
            {
                System.out.println("@@@:TabbedContainerActionCommand = " + e.getActionCommand());
                String command = e.getActionCommand().toLowerCase();
                if ("select".equals(command))
                {
                    treePathLst.clear();
                    // 切换TAB时，让textarea获得焦点.
                    focusOnEditor();
                }
            }
        });

    }

    public int getTabIndex(TabData tab)
    {
        int index = -1;
        for (int i = 0; i < tabDataModel.size(); i++)
        {
            TabData t = tabDataModel.getTab(i);
            if (t.equals(tab))
            {
                index = i;
                break;
            }
        }
        return index;
    }

    public void setTabIcon(TabData tabData, Icon icon)
    {
        int index = tabDataModel.indexOf(tabData);
        tabDataModel.setIcon(index, icon);
    }

    public void setTabTitle(TabData tabData, String title)
    {
        int index = tabDataModel.indexOf(tabData);
        tabDataModel.setText(index, title);
    }

    public void showAboutBox()
    {
        if (aboutBox == null)
        {
            JFrame mainFrame = MainApp.getApplication().getMainFrame();
            aboutBox = new MainAboutBox(mainFrame);
            aboutBox.setLocationRelativeTo(mainFrame);
        }
        MainApp.getApplication().show(aboutBox);
    }

    private TabData newTabData(String tabName, String tabTip, Icon icon)
    {

        InterPanel pane = new InterPanel(this);
        TabData tabData = new TabData(pane, icon, tabName, tabTip);
        pane.setTabData(tabData);
        return tabData;
    }

    private InterPanel addTab(String tabName, boolean isSel, Icon icon)
    {
        TabData tabData = newTabData(tabName, tabName, icon);
        int newIndex = tabbedContainer.getTabCount();
        tabDataModel.addTab(newIndex, tabData);
        if (isSel)
        {
            tabbedContainer.getSelectionModel().setSelectedIndex(newIndex);
        }
        focusOnEditor();
        return (InterPanel) tabData.getComponent();
    }

    /**
     * 编辑器获得焦点
     */
    private void focusOnEditor()
    {
        SwingUtilities.invokeLater(new Runnable()
        {
            public void run()
            {
                getActiveEditor().requestFocus();
            }
        });
    }

    private InterPanel getActiveContentPanel()
    {
        int selIndex = getTabIndex();
        if (selIndex >= 0)
        {
            TabData selTabData = tabDataModel.getTab(selIndex);
            InterPanel panel = (InterPanel) selTabData.getComponent();
            return panel;
        }
        return null;
    }

    private JsonPanel getActiveJsonPanel()
    {
        int selIndex = getTabIndex();
        if (selIndex >= 0)
        {
            TabData selTabData = tabDataModel.getTab(selIndex);
            JTabbedPane tabPane = (JTabbedPane) selTabData.getComponent();
            JsonPanel pane = (JsonPanel) tabPane.getSelectedComponent();
            return pane;
        }
        return null;
    }

    private JTextArea getActiveEditor()
    {
        return getActiveJsonPanel().getEditor();
    }

    private JTree getTree(TabData tabData)
    {
        if (tabData == null)
        {
            return null;
        }

        InterPanel contentPanel = (InterPanel) tabData.getComponent();
        if (contentPanel.getSelectedIndex() == 0)
        {
            return contentPanel.getRequestPanel().getNodeTree();
        } else
        {
            return contentPanel.getResponsePanel().getNodeTree();
        }
    }

    private JTree getTree(int tabIndex)
    {
        if (tabIndex >= 0)
        {
            TabData selTabData = tabDataModel.getTab(tabIndex);
            return getTree(selTabData);
        }
        return null;
    }

    private JTree getTree()
    {
        return getTree(getTabIndex());
    }
    
    public void switchPanel()
    {
        int index = getActiveContentPanel().getSelectedIndex();
        if (index == 1)
        {
            getActiveContentPanel().setSelectedIndex(0);
        } else 
        {
            getActiveContentPanel().setSelectedIndex(1);
        }
    }
        

    private void modifyDialgTitle(JDialog dlg, boolean flag, int n)
    {
        String[] tmp = dlg.getTitle().split("-");
        if (n == -1)
        {
            dlg.setTitle(tmp[0] + "-" + "  ==");
            return;
        }
        if (flag)
        {
            dlg.setTitle(tmp[0] + "-" + "  找到了O(∩_∩)O");
        } else
        {
            dlg.setTitle(tmp[0] + "-" + "  没找到╮(╯_╰)╭");
        }
    }

    private TreePath expandTreeNode(JTree tree, TreeNode[] arr, Boolean expand)
    {
        TreePath[] tp = new TreePath[arr.length];
        tp[0] = new TreePath(arr[0]);
        int pos = 0;
        for (int i = 1; i < arr.length; i++)
        {
            tp[i] = tp[i - 1].pathByAddingChild(arr[i]);
        }
        for (int i = 0; i < arr.length; i++)
        {
            if (expand)
            {
                tree.expandPath(tp[i]);
            } else
            {
                tree.collapsePath(tp[i]);
            }
            pos = i;
        }
        return tp[pos];
    }

    private void findTreeChildValue(String findText, List<TreePath> treePathLst)
    {
        JTree tree = getTree();
        DefaultMutableTreeNode root = (DefaultMutableTreeNode) tree.getModel().getRoot();
        Enumeration e = root.depthFirstEnumeration();
        treePathLst.clear();
        curPos = 0;
        while (e.hasMoreElements())
        {
            DefaultMutableTreeNode node = (DefaultMutableTreeNode) e.nextElement();
            if (node.isLeaf())
            {
                String str = node.toString();
                if (str.substring(2).indexOf(findText) >= 0)
                {
                    tree.expandPath(new TreePath(node.getPath()));
                    TreePath tp = expandTreeNode(tree, node.getPath(), true);
                    treePathLst.add(tp);
                }
            }
        }
        if (!treePathLst.isEmpty())
        {
            tree.setSelectionPath(treePathLst.get(0));
            tree.scrollPathToVisible(treePathLst.get(0));
        }
//        return treePathLst;
    }

    /**
     * 文本内容查找定位
     * @param key 要查找的字符串
     * @param ignoreCase 是否区分大小写
     * @param down  查找方向（向上false，向下true）
     * @param isFirst 是否从开头开始查找
     * @return
     */
    public boolean startSegmentFindOrReplaceOperation(JTextArea textArea, String key, boolean ignoreCase, boolean down, boolean isFirst)
    {
        int length = key.length();
        Document doc = textArea.getDocument();
        int offset = textArea.getCaretPosition();
        int charsLeft = doc.getLength() - offset;
        if (charsLeft <= 0)
        {
            offset = 0;
            charsLeft = doc.getLength() - offset;
        }
        if (!down)
        {
            offset -= length;
            offset--;
            charsLeft = offset;
        }
        if (isFirst)
        {
            offset = 0;
            charsLeft = doc.getLength() - offset;
        }
        Segment text = new Segment();
        text.setPartialReturn(true);
        try
        {
            while (charsLeft > 0)
            {
                doc.getText(offset, length, text);
                if ((ignoreCase == true && text.toString().equalsIgnoreCase(key))
                        || (ignoreCase == false && text.toString().equals(key)))
                {
                    //textArea.requestFocus();////焦点,才能能看到效果
                    textArea.setSelectionStart(offset);
                    textArea.setSelectionEnd(offset + length);
                    return true;
                }
                charsLeft--;
                if (down)
                {
                    offset++;
                } else
                {
                    offset--;
                }

            }
        } catch (Exception e)
        {
        }
        return false;
    }

    private void openFileAction()
    {
        String title = $("openDlg.text");
        java.awt.FileDialog openDlg = new java.awt.FileDialog(getFrame(), title, java.awt.FileDialog.LOAD);
        openDlg.setLocationRelativeTo(null);
        openDlg.setVisible(true);
        if (null == openDlg.getDirectory() || null == openDlg.getFile())
        {
            return;
        }

        File file = new File(openDlg.getDirectory(), openDlg.getFile()); //fc.getSelectedFile();
        openFile(file);
    }

    private void openFile(File file)
    {
        if (file == null || !file.exists())
        {
            return;
        }

        // 如果选择的文件已经打开了，则直接打开该标签页
        for (int i = 0; i < tabDataModel.getTabs().size(); i++)
        {
            TabData tabData = tabDataModel.getTab(i);
            InterPanel p = (InterPanel) tabData.getComponent();
            if (file.equals(p.file))
            {
                tabbedContainer.getSelectionModel().setSelectedIndex(i);
                focusOnEditor();
                return;
            }
        }

        BufferedReader reader = null;
        StringBuilder sb = new StringBuilder();
        try
        {
            InputStreamReader isr = new InputStreamReader(new FileInputStream(file), "GBK");
            reader = new BufferedReader(isr);
            String temp = null;
            while ((temp = reader.readLine()) != null)
            {
                sb.append(temp).append("\n");
            }
            reader.close();
        } catch (IOException e)
        {
        } finally
        {
            if (reader != null)
            {
                try
                {
                    reader.close();
                } catch (IOException e1)
                {
                }
            }
        }

        addRecentFile(file);
        InterPanel contentPanel = addTab(file.getName(), true, $icon("tab.icon3"));
        contentPanel.file = file;
        contentPanel.getRequestEditor().setText(sb.toString());
        tabbedContainer.setToolTipTextAt(getTabIndex(), file.getAbsolutePath());
        //contentPanel.getRequestPanel().formatJson();
    }

    /**
     * 将文件添加到“最近打开的文件”菜单里
     * @param file 
     */
    private void addRecentFile(final File file)
    {
        int recent = recentFilesMenu.getMenuComponentCount();
        JMenuItem existItem = null;    // 最来判断“最近打开的文件”是否包含了此文件
        for (int i = 0; i < recent; i++)
        {
            JMenuItem item = recentFilesMenu.getItem(i);
            if (file.getAbsolutePath().equals(item.getName()))
            {
                existItem = item;
                recentFilesMenu.remove(item);
                break;
            }
        }

        // 如果已经存在，则将其移动到最上面
        if (null != existItem)
        {
            recentFilesMenu.add(existItem, 0);
            return;
        }

        // 最近打开的文件 中没有此文件，则在顶部新增一个菜单，最大菜单个数是20
        if (recent >= 20)
        {
            recentFilesMenu.remove(recent - 1);
        }
        existItem = new JMenuItem(file.getAbsolutePath());
        existItem.setName(file.getAbsolutePath());
        existItem.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e)
            {
                openFile(file);
            }
        });
        recentFilesMenu.add(existItem, 0);
        updateRecentFiles();
    }

    private void codeChangeAction()
    {
        javax.swing.JDialog dlg = new javax.swing.JDialog(getFrame());
        dlg.setTitle($("menuItemCode.text"));
        dlg.setSize(500, 350);
        dlg.setMinimumSize(new Dimension(500, 350));
        JSplitPane spiltPane2 = new JSplitPane();
        spiltPane2.setDividerLocation(150);
        spiltPane2.setOrientation(JSplitPane.VERTICAL_SPLIT);

        final JTextArea textAreaSrc = new JTextArea();
        final JTextArea textAreaDest = new JTextArea();
        textAreaSrc.setLineWrap(true);
        textAreaDest.setLineWrap(true);

        spiltPane2.setTopComponent(new JScrollPane(textAreaSrc));
        spiltPane2.setBottomComponent(new JScrollPane(textAreaDest));

        JButton btnOK = new JButton("转换");
        btnOK.setSize(50, 25);
        java.awt.Container pane = dlg.getContentPane();
        BorderLayout layout = new BorderLayout();
        //layout.addLayoutComponent(spiltPane, BorderLayout.CENTER);
        // layout.addLayoutComponent(btnOK, BorderLayout.SOUTH);
        pane.setLayout(layout);
        pane.add(spiltPane2, BorderLayout.CENTER);
        pane.add(btnOK, BorderLayout.SOUTH);

        btnOK.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent e)
            {
                String str = textAreaSrc.getText();
                str = StringEscapeUtils.unescapeJava(str);
                textAreaDest.setText(str);
            }
        });
        MainApp.getApplication().show(dlg);

    }

    private void saveFileAction(String data)
    {
        // 如果是已打开的文件，则直接保存，否则弹出文件对话框
        File file = getActiveContentPanel().file;
        if (file == null)
        {
            saveFileAsAction(data);
        } else {
            saveFile(file, data);
        }
    }
    
    private void saveFileAsAction(String data)
    {
        String title = $("closeDlg.text");
        java.awt.FileDialog saveDlg = new java.awt.FileDialog(getFrame(), title, java.awt.FileDialog.SAVE);
        saveDlg.setVisible(true);
        if (null == saveDlg.getDirectory() || null == saveDlg.getFile())
        {
            return;
        }

        File file = new File(saveDlg.getDirectory(), saveDlg.getFile());

        Icon icon = $icon("tab.icon3");
        int selectedIndex = getTabIndex();
        getActiveContentPanel().file = file;
        getActiveContentPanel().icon = icon;
        tabbedContainer.setIconAt(selectedIndex, icon);
        tabDataModel.setText(selectedIndex, file.getName());
        tabbedContainer.setToolTipTextAt(selectedIndex, file.getAbsolutePath());
        addRecentFile(file);   // 添加到 最近打开的文件 菜单里
        saveFile(file, data);
    }
    
    private void saveFile(File file, String data)
    {
        if (file == null || file.getPath().length() == 0)
        {
            return;
        }


        BufferedWriter write = null;
        StringBuilder sb = new StringBuilder();
        try
        {
            OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(file), "GBK");
            write = new BufferedWriter(osw);
            String text = StringUtils.replace(data, "\n", "\r\n");
            write.write(text, 0, text.length());
            write.close();
        } catch (IOException e)
        {
        } finally
        {
            if (write != null)
            {
                try
                {
                    write.close();
                } catch (IOException e1)
                {
                }
            }
        }
    }

    public void dragEnter(DropTargetDragEvent dtde) {}

    public void dragOver(DropTargetDragEvent dtde) {}

    public void dropActionChanged(DropTargetDragEvent dtde) {}

    public void dragExit(DropTargetEvent dte) {}

    /**
     * 实现文件拖放打开
     * @param dtde 
     */
    public void drop(DropTargetDropEvent dtde)
    {
        try
        {
            // Transferable tr = dtde.getTransferable();
            if (dtde.isDataFlavorSupported(DataFlavor.javaFileListFlavor))
            {
                dtde.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
                List list = (List) (dtde.getTransferable().getTransferData(DataFlavor.javaFileListFlavor));
                Iterator iterator = list.iterator();
                while (iterator.hasNext())
                {
                    File file = (File) iterator.next();
                    if (null != file && null != file.getAbsolutePath())
                    {
                        openFile(file);
                    }
                }
                dtde.dropComplete(true);
            } else
            {
                dtde.rejectDrop();
            }
        } catch (IOException ioe)
        {
            ioe.printStackTrace();
        } catch (UnsupportedFlavorException ufe)
        {
            ufe.printStackTrace();
        }
    }
}
